/*
 * Created on Feb 11, 2005
 * Created by dfhuynh
 */
package edu.mit.simile.longwell.query.project;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import com.hp.hpl.jena.rdf.model.Model;

import edu.mit.simile.longwell.CascadedCache;
import edu.mit.simile.longwell.Profile;
import edu.mit.simile.longwell.ProfileListenerBase;
import edu.mit.simile.longwell.query.QueryException;

/**
 * @author dfhuynh
 */
public class ProjectorManager extends ProfileListenerBase {
	final protected Profile	m_profile;
	final protected Map		m_projectorNameToFamily = new HashMap();
	
	protected Set m_cachedProjectors;
	
	protected class ProjectorFamily {
		Constructor		m_constructor;
		CascadedCache	m_localeToParameterToProjector;
	}
	
	public ProjectorManager(Profile profile) {
		m_profile = profile;
	}
	
	public IProjector getProjector(
			String name, String parameter, String locale) throws QueryException {
		
		if (name == null) {
			name = PropertyProjector.class.getName();
		}
		if (locale == null) {
			locale = "";
		}
		
		ProjectorFamily family = (ProjectorFamily) 
			m_projectorNameToFamily.get(name);
		
		if (family == null) {
			try {
				family = new ProjectorFamily();
				family.m_constructor = 
					Class.forName(name).getConstructor(
						new Class[] { 
							Profile.class, String.class, String.class });
				family.m_localeToParameterToProjector = new CascadedCache(
					ProjectorManager.class,
					"locale", 5,
					"parameter", 100
				);
				
				m_projectorNameToFamily.put(name, family);
			} catch (Exception e) {
				throw new QueryException(
					"Failed to create projector family of name " + name,
					e);
			}
		}
		
		IProjector projector = (IProjector) 
			family.m_localeToParameterToProjector.get(locale, parameter);
		
		if (projector == null) {
			try {
				projector = (IProjector) family.m_constructor.newInstance(
					new Object[] { m_profile, parameter, locale });
			
				family.m_localeToParameterToProjector.put(locale, parameter, projector);
				
				m_cachedProjectors = null;
			} catch (Exception e) {
				throw new QueryException(
					"Failed to create projector of name " + name,
					e);
			}
		}
		
		return projector;
	}
		
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.ProfileListenerBase#onBeforeAdd(com.hp.hpl.jena.rdf.model.Model)
	 */
	public void onBeforeAdd(Model model) {
		Iterator i = getProjectors().iterator();
		while (i.hasNext()) {
			IProjector projector = (IProjector) i.next();
			
			projector.onBeforeAdd(model);
		}
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.ProfileListenerBase#onAfterAdd(com.hp.hpl.jena.rdf.model.Model)
	 */
	public void onAfterAdd(Model model) {
		Iterator i = getProjectors().iterator();
		while (i.hasNext()) {
			IProjector projector = (IProjector) i.next();
			
			projector.onAfterAdd(model);
		}
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.ProfileListenerBase#onFailingAdd(com.hp.hpl.jena.rdf.model.Model)
	 */
	public void onFailingAdd(Model model) {
		Iterator i = getProjectors().iterator();
		while (i.hasNext()) {
			IProjector projector = (IProjector) i.next();
			
			projector.onFailingAdd(model);
		}
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.ProfileListenerBase#onBeforeRemove(com.hp.hpl.jena.rdf.model.Model)
	 */
	public void onBeforeRemove(Model model) {
		Iterator i = getProjectors().iterator();
		while (i.hasNext()) {
			IProjector projector = (IProjector) i.next();
			
			projector.onBeforeRemove(model);
		}
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.ProfileListenerBase#onAfterRemove(com.hp.hpl.jena.rdf.model.Model)
	 */
	public void onAfterRemove(Model model) {
		Iterator i = getProjectors().iterator();
		while (i.hasNext()) {
			IProjector projector = (IProjector) i.next();
			
			projector.onAfterRemove(model);
		}
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.ProfileListenerBase#onFailingRemove(com.hp.hpl.jena.rdf.model.Model)
	 */
	public void onFailingRemove(Model model) {
		Iterator i = getProjectors().iterator();
		while (i.hasNext()) {
			IProjector projector = (IProjector) i.next();
			
			projector.onFailingRemove(model);
		}
	}

	protected Set getProjectors() {
		if (m_cachedProjectors == null) {
			m_cachedProjectors = new HashSet();
			
			Iterator i = m_projectorNameToFamily.values().iterator();
			while (i.hasNext()) {
				ProjectorFamily family = (ProjectorFamily) i.next();
				
				family.m_localeToParameterToProjector
					.collectSecondLevelValues(m_cachedProjectors);
			}
		}
		return m_cachedProjectors;
	}

}
